package com.roin.tools.service;

import org.apache.commons.codec.digest.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
 * 文件夹比较业务类
 * @author Roin
 */
public class DirCompareService {

    /**
     * 目录比较
     * @param sourceDir 源目录
     * @param targetDir 目标目录
     * @param fileTypeLimitList 文件类型限制
     * @param copy 是否复制
     * @param tempPath 复制文件保存目录
     * @param keepPath 复制时是否保留原有的目录结构
     */
    public List<File> compareDir(File sourceDir,File targetDir, Set<String> fileTypeLimitList, boolean copy, String tempPath, boolean keepPath) throws Exception {
        //用于保存目标目录有，而源目录没有的文件信息
        List<File> resultFiles = new ArrayList<>();


        //获得源目录的所有文件集合
        List<File> sourceFiles = new ArrayList<>();
        getAllFile(sourceDir,sourceFiles,fileTypeLimitList,null);

        Set<String> sourceMd5Set = new HashSet<>(2);
        for (File file : sourceFiles) {
            String md5Str =  DigestUtils.md5Hex(new FileInputStream(file));
            sourceMd5Set.add(md5Str);
        }

        //获得目标目录的所有文件集合
        List<File> targetFiles = new ArrayList<>();
        getAllFile(targetDir,targetFiles,fileTypeLimitList,null);

        Map<String, File> targetMd5Map = new HashMap<>(2);
        for (File file : targetFiles) {
            String md5Str =  DigestUtils.md5Hex(new FileInputStream(file));
            targetMd5Map.put(md5Str,file);
        }
        //开始查找目标目录有，而源目录没有的文件
        targetMd5Map.forEach((md5Str,file)->{
            if(!sourceMd5Set.contains(md5Str)){
                resultFiles.add(file);
            }
        });

        if (copy){
            System.out.println("共找到了"+resultFiles.size()+"个文件，开始复制到指定目录...");
            File tempDir = new File(tempPath);
            if(!tempDir.exists() || !tempDir.isDirectory()){
                tempDir.mkdirs();
            }
            File newFile;
            String targetPath = targetDir.getAbsolutePath();
            for (File file : resultFiles) {
                String newFilePath = tempPath +(keepPath ?(file.getPath().replace(targetPath,"")):(File.separator+file.getName()));
                newFile = new File(newFilePath);
                if (!newFile.exists()){
                    newFile.mkdirs();
                }
                try {
                    Files.copy(file.toPath(),newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                } catch (Exception e) {
                    System.err.println(String.format("复制文件%失败：%s",file.getAbsolutePath(),e.getMessage()));
                }
            }
            System.out.println("复制完成！");
        }

        return resultFiles;
    }

    /**
     * 迭代遍历获取目录的所有文件
     * @param dir
     * @param fileList
     * @param excludeDirs
     */
    private void getAllFile(File dir, List<File> fileList, Set<String> fileTypeLimitList, Set<String> excludeDirs){
        boolean hasFileTypeLimit = !(fileTypeLimitList==null||fileTypeLimitList.isEmpty());
        if (dir.exists() && dir.isDirectory()){
            File[] subFileList = dir.listFiles();
            System.out.println(String.format("正在获取【%s】目录下的文件，共%s文件和目录...",dir.getPath(),subFileList.length));
            for (File file : subFileList) {
                String name = file.getName();
                if (file.isFile()){
                    if (hasFileTypeLimit){
                        for (String type : fileTypeLimitList) {
                            if (name.endsWith(type)){
                                fileList.add(file);
                            }
                        }
                    }else{
                        fileList.add(file);
                    }
                }else{
                    if(excludeDirs==null || !excludeDirs.contains(file.getName())){
                        getAllFile(file, fileList, fileTypeLimitList, excludeDirs);;
                    }
                }
            }
        }
    }
}
